#!/usr/bin/env python
from CVSConstants import *
import gobject
import gtk
import subprocess
import os
import signal

PULSE_INTERVAL = 100

class CVSModel(object):
  def __init__(self):
    self.observers = {}
    self.sources = []
    self.cvs = None

  def addObserver(self, signal, ob):
    obs = self.observers.setdefault(signal, [])
    obs.append(ob)

  def removeObserver(self, signal, ob):
    obs = self.observers[signal]
    obs.remove(ob)
    
  def getAction(self):
    return 'CVS'
  
  def getActivity(self):
    return 'Working'

  def _notify(self, signal, *args):
    obs = self.observers.setdefault(signal, [])
    for ob in obs:
      ob(self, *args)

  def _createCmd(self):
    raise NotImplementedError
   
  def _startCVS(self):
    try:
      cmd = self._createCmd()
    except RuntimeError:
      gtk.main_quit()
      return
    os.chdir(CVS_PATH)
    self._notify('cvs-started', CVS_PATH, ' '.join(cmd))
    self.cvs = subprocess.Popen(cmd, stdout=subprocess.PIPE, 
                                stderr=subprocess.PIPE)
    i = gobject.io_add_watch(self.cvs.stdout, gobject.IO_IN, self._readCVS)                                  
    self.sources.append(i)
    i = gobject.io_add_watch(self.cvs.stderr, gobject.IO_IN, self._readCVS)
    self.sources.append(i)
    i = gobject.timeout_add(PULSE_INTERVAL, self._waiting)
    self.sources.append(i)

  def _waiting(self):
    rv = self.cvs.poll()
    if rv is None:
      self._notify('cvs-waiting')
      return True
    else:
      out, err = self.cvs.communicate()
      if out:
        self._notify('cvs-message-received', out)
      if err:
        self._notify('cvs-error-received', err)
      self._notify('cvs-closed', rv)
      map(gobject.source_remove, self.sources)
      return False

  def _readCVS(self, source, condition):
    try:
      text = source.read()
    except EOFError:
      return False
    if source == self.cvs.stdout:
      self._notify('cvs-message-received', text)
    else:
      self._notify('cvs-error-received', text)
    return True

  def start(self):
    gobject.timeout_add(1, self._startCVS)
    gtk.main()

  def end(self):
    try:
      os.kill(self.cvs.pid, signal.SIGINT)
    except (AttributeError, OSError):
      pass
    gtk.main_quit()
